%
% grammar
%
\def\S{{\it s\ }}
\def\N{{\it n\ }}
\section Expression Grammar

Expressions are used for queries, for defaults of card items, and for
printing expressions into cards. They are set in Database Edit mode; a
normal user does not deal with expressions directly.

Expressions deal with two data types, {\it strings}\/ and {\it numbers}.
Expressions or sub-expressions returning strings are enclosed in braces;
expressions or sub-expressions returning numbers are enclosed in parentheses.
There are many built-in operators and functions; most of them can be used
only in either string or numeric context.

Numbers begin with a numerical digit or a period, and are in standard
integer, floating-point, or exponential notation. String literals are
enclosed in double quotes. Conversions from numbers to strings use the
{\tt \%g} format (unless {\tt printf} is used); conversions from strings
to numbers skips leading blanks and converts like {\tt atof}. Trailing
non-numeric characters are ignored.

Expressions are interpreted, not compiled. This means that all parts of
the expression are evaluated, {\tt ?:}, {\tt \&\&}, and {\tt $||$} do not
short-circuit.

In the following tables, \N stands for a number ot a numerical expression,
and \S stands for a literal string or a string expression. Note that some
operators, such as {\tt ==} and {\tt date}, appear in both contexts.

\subsection Numerical Operations

Divisions by zero return $1$. Arithmetic operators
use standard C precedences. Bitwise operations operate on 32 bits only.

\cleartabs
\settabs \+ mmmmmmmmmmm & mmmm & mmmmmmmmmmmmmmmmmmmmmmmmm\cr
\medskip
\+   {\it Operator} & {\it Type} & {\it Operation}\cr
\smallskip\hrule\smallskip
\+   {\tt (} \N {\tt )} & \N & Number\cr
\+   {\tt $\{$} \S {\tt $\}$} & \N & In number context, convert string to a number\cr
\+   \N {\tt ?} \N {\tt :} \N & \N & If the first number is nonzero, return the second number;\cr
\+   && otherwise, return the third number\cr
\+   \N {\tt ,} \N & \N & Evaluate both numbers, return second\cr
\+   {\tt -} \N & \N & Unary minus\cr
\+   {\tt !} \N & \N & Unary boolean NOT\cr
\+   $\sim$ \N & \N & Unary bitwise NOT\cr
\+   \N {\tt +} \N & \N & Add two numbers\cr
\+   \N {\tt -} \N & \N & Subtract two numbers\cr
\+   \N {\tt *} \N & \N & Multiply two numbers\cr
\+   \N {\tt /} \N & \N & Divide two numbers\cr
\+   \N {\tt \%} \N & \N & Calculate modulo of two numbers\cr
\+   \N {\tt \&} \N & \N & Calculate bitwise AND of two numbers\cr
\+   \N {\tt \&\&} \N & \N & Calculate boolean AND of two numbers\cr
\+   \N {\tt |} \N & \N & Calculate bitwise OR of two numbers\cr
\+   \N {\tt ||} \N & \N & Calculate boolean OR of two numbers\cr
\+   \N \^ \N & \N & Calculate bitwise XOR of two numbers\cr
\+   \N {\tt <<} \N & \N & Calculate bitwise left shift\cr
\+   \N {\tt >>} \N & \N & Calculate bitwise right shift\cr
\+   \N {\tt ==} \N & \N & 1 if both numbers are equal, 0 otherwise\cr
\+   \N {\tt !=} \N & \N & 1 if both numbers are not equal, 0 otherwise\cr
\+   \N {\tt <} \N & \N & 1 if the first number is less than the second, 0 otherwise\cr
\+   \N {\tt >} \N & \N & 1 if the first number is greater than the second, 0 otherwise\cr
\+   \N {\tt <=} \N & \N & 1 if the first number is less than or equal to the second, 0 otherwise\cr
\+   \N {\tt >=} \N & \N & 1 if the first number is greater than or equal to the second, 0 otherwise\cr
\+   {\tt sqrt (} \N {\tt )} & \N & Square root of a number\cr
\+   {\tt exp (} \N {\tt )} & \N & Exponential function, $e^n$\cr
\+   {\tt log (} \N {\tt )} & \N & Decimal logarithm, $\log_{10} n$\cr
\+   {\tt ln (} \N {\tt )} & \N & Natural logarithm, $\log_e n$\cr
\+   {\tt pow (} \N, \N {\tt )} & \N & First number raised to the second, $n^m$\cr
\+   {\tt sin (} \N {\tt )} & \N & Sine of a number, $\sin x$\cr
\+   {\tt cos (} \N {\tt )} & \N & Cosine of a number, $\cos x$\cr
\+   {\tt tan (} \N {\tt )} & \N & Tangent of a number, $\tan x$\cr
\+   {\tt asin (} \N {\tt )} & \N & Arc sine of a number, $\sin^{-1} x$\cr
\+   {\tt acos (} \N {\tt )} & \N & Arc cosine of a number, $\cos^{-1} x$\cr
\+   {\tt atan (} \N {\tt )} & \N & Arctangent of a number, $\tan^{-1} x$\cr
\+   {\tt atan2 (} \N, \N {\tt )} & \N & Quadrant-aligned arctangent\cr
\+   {\tt len (} \S {\tt )} & \N & Length of a string\cr
\+   {\tt bound (} \N, \N, \N {\tt )} & \N & The first number bounded by a minimum (second number) and\cr
\+   && a maximum (third number)\cr
\bigskip

\subsection String Operations

Note that string comparisons return strings, and must be enclosed in braces
$\{\}$ if \&\& or || or other numerical operators are used on the result.

\medskip
\+   {\it Operator} & {\it Type} & {\it Operation}\cr
\smallskip\hrule\smallskip
\+   {\tt $\{$} \S {\tt $\}$} & \S & String\cr
\+   {\tt (} \N {\tt )} & \S & In string context, convert number to a string\cr
\+   \S {\tt ;} \S & \S & Evaluate both strings, return second\cr
\+   \S {\tt .} \S & \S & Concatenate strings\cr
\+   \S {\tt ?} \S {\tt :} \S & \S & If the numeric value of the first string is nonzero, return the second string;\cr
\+   && otherwise, return the third string\cr
\+   \S {\tt ==} \S & \S & Return {\tt "1"} if the two strings match; otherwise, return {\tt "0"}\cr
\+   \S {\tt !=} \S & \S & Return {\tt "1"} if the two strings do not match; otherwise, return {\tt "0"}\cr
\+   \S {\tt <} \S & \S & Return {\tt "1"} if the first string is lexicographically less than the second\cr
\+   && string; otherwise, return {\tt "0"}\cr
\+   \S {\tt >} \S & \S & Return {\tt "1"} if the first string is lexicographically greater than the second\cr
\+   && string; otherwise, return {\tt "0"}\cr
\+   \S {\tt <=} \S & \S & Return {\tt "1"} if the first string is lexicographically less than or equal to the\cr
\+   && second string; otherwise, return {\tt "0"}\cr
\+   \S {\tt >=} \S & \S & Return {\tt "1"} if the first string is lexicographically greater than or equal to\cr
\+   \S {\tt in} \S & \S & Return {\tt "1"} if the first string is contained in the second string; otherwise,\cr
\+   && return {\tt "0"}\cr
\+   {\tt chop (} \S {\tt )} & \S & Return the string with the trailing newline, if any, removed\cr
\+   {\tt substr (} \S, \N, \N {\tt )} & \S & Return a substring of the first string. The first number is the start index\cr
\+   && and the second the length. A negative index counts from the end.\cr
\+   {\tt printf (} {\it args} {\tt )} & \S & Format and return a string; {\it args} is a comma-separated list of expressions.\cr
\+   && Compound expressions must be enclosed in (~) or $\lbrace~\rbrace$.\cr
\bigskip

\subsection Variables

Variables are letters {\tt a} through {\tt z} that can hold strings or
numbers. When a variable is assigned to, the result of the assignment is
returned. All variables are reset to the empty string (or 0) when a database
is loaded from disk.

\medskip
\+   {\it Operator} & {\it Type} & {\it Operation}\cr
\smallskip\hrule\smallskip
\+   {\it var} & \S,\N & Value of a variable\cr
\+   {\it var} {\tt =} \S & \S & Assign string value to a variable\cr
\+   {\it var} {\tt =} \N & \N & Assign numeric value to a variable\cr
\+   {\it var} {\tt .=} \S & \S & Append string to a variable\cr
\+   {\it var} {\tt +=} \N & \N & Add a number to a variable\cr
\+   {\it var} {\tt -=} \N & \N & Subtract a number from a variable\cr
\+   {\it var} {\tt *=} \N & \N & Multiply a variable by a number\cr
\+   {\it var} {\tt /=} \N & \N & Divide a variable by a number\cr
\+   {\it var} {\tt \%=} \N & \N & Assign modulo with a number to variable\cr
\+   {\it var} {\tt \&=} \N & \N & Perform logical AND with a variable\cr
\+   {\it var} {\tt |=} \N & \N & Perform logical OR with a variable\cr
\+   {\it var} {\tt ++} & \N & Post-increment variable\cr
\+   {\it var} {\tt --} & \N & Post-decrement variable\cr
\+   {\tt ++} {\it var} & \N & Pre-increment variable\cr
\+   {\tt --} {\it var} & \N & Pre-decrement variable\cr
\bigskip

\subsection Database Access

Database rows (cards) can be accessed by providing an
index in brackets. Without brackets, the current card ({\tt this}) is
assumed. Database columns are named. The name must always be prefixed
with an underscore (\_). In place of the name, the field can be selected
with a column number (which must also be prefixed with an underscore),
beginning at 0. Only fields that store data in the database can be
accessed (types {\it Input}, {\it Time}, {\it Flag}, and {\it Choice});
this excludes fields of type {\it Label}\/ and {\it Print}.

The {\tt avg}, {\tt dev}, {\tt min}, {\tt max}, and {\tt sum} operators
differ from all other operators: they don't reference a field in the
current or any single card, they operate on a field in all cards by
accessing an entire column of the database. These operators are also
available as {\tt qavg}, {\tt qdev}, {\tt qmin}, {\tt qmax}, and {\tt
qsum}, which apply the calculation only to the result of the last
query (i.e., to the cards displayed in the summary). Finally, the {\tt
savg}, {\tt sdev}, {\tt smin}, {\tt smax}, and {\tt qsum} variations
are applied to all cards in the current section; if there are no
sections or if all sections are selected, all cards are considered.

The {\tt switch} statement is legal only in {\it Action when pressed}
expressions for Button-type fields in the form editor. It does nothing
except as action for a button in a card. It switches \grok\ to a new
form as if the Database pulldown had been used (see the Editing Forms
chapter for details about the difference between {\it databases} and
{\it forms}. The first argument is the new form name, the second argument
is the query expression or search string that determines which cards
are displayed in the summary initially. The possible combinations are:

\itm{\tt search("", "")}\hfill\break
Does nothing.

\itm{\tt search("", "*")}\hfill\break
Keep the current form, and put all cards in the summary.

\itm{\tt search("", "$\{$expr$\}$")}\hfill\break
Keep the current form, and put all cards in the summary for which
{\it expr} returns something other than 0 or the empty string.

\itm{\tt search("", "(expr)")}\hfill\break
Equivalent to the previous, except that the returned string is converted
to a number, which is checked for nonzero values.

\itm{\tt search("", "string")}\hfill\break
Keep the current form, and put all cards in the summary whose searchable
fields contain {\it string}.

\itm{\tt search("name", "")}\hfill\break
Switch to form {\it name}, and display all cards in the summary.

\itm{\tt search("name", "xxx")}\hfill\break
Switch to form {\it name}, and then perform a query. {\tt xxx} stands
for any of the above query expressions.

Because short-circuiting doesn't work, {\tt switch} can't depend on a
conditional, but its two arguments can. {\tt switch} returns the empty
string, which means that the button won't execute a command as usual;
if this is overridden by appending a semicolon and another string
expression, the command is executed after the database switch. To execute
a script before switching, prepend a {\tt system} statement and a
semicolon to the {\tt switch} statement (the switch is done after the
expression is completely evaluated). To switch back to the previous
form, use the {\tt prevform} statement.

\medskip
\+   {\it Operator} & {\it Type} & {\it Operation}\cr
\smallskip\hrule\smallskip
\+   {\it \_field} & \S,\N & A field from the database, of current card\cr
\+   {\it \_field} {\tt [} \N {\tt ]}& \S,\N & A field from the database, from any card\cr
\+   {\tt this} & \N & The number of the current card, 0 is first\cr
\+   {\tt last} & \N & The number of the last card, 0 is first\cr
\+   {\tt avg (} {\it \_field} {\tt )} & \N & Average of a field in all cards\cr
\+   {\tt qavg (} {\it \_field} {\tt )} & \N & Average the current query result\cr
\+   {\tt savg (} {\it \_field} {\tt )} & \N & Average the current section\cr
\+   {\tt dev (} {\it \_field} {\tt )} & \N & Standard deviation of a field in all cards\cr
\+   {\tt qdev (} {\it \_field} {\tt )} & \N & Std. dev. of the current query result\cr
\+   {\tt sdev (} {\it \_field} {\tt )} & \N & Std. dev. of the current section\cr
\+   {\tt min (} {\it \_field} {\tt )} & \N & Minimum value of a field in all cards\cr
\+   {\tt qmin (} {\it \_field} {\tt )} & \N & Minimum of the current query result\cr
\+   {\tt smin (} {\it \_field} {\tt )} & \N & Minimum of the current section\cr
\+   {\tt max (} {\it \_field} {\tt )} & \N & Maximum value of a field in all cards\cr
\+   {\tt qmax (} {\it \_field} {\tt )} & \N & Maximum value of the current query result\cr
\+   {\tt smax (} {\it \_field} {\tt )} & \N & Maximum value of the current section\cr
\+   {\tt sum (} {\it \_field} {\tt )} & \N & Sum of a field in all cards\cr
\+   {\tt qsum (} {\it \_field} {\tt )} & \N & Sum of the current query result\cr
\+   {\tt ssum (} {\it \_field} {\tt )} & \N & Sum of the current section\cr
\+   {\tt dbase} & \S & The name of the accessed database file\cr
\+   {\tt form} & \S & The name of the accessed form file\cr
\+   {\tt section} & \S & The name of the current section, or the empty string\cr
\+   {\tt section} & \N & The number of the section the current card is in, or 0\cr
\+   {\tt section [} \N {\tt ]} & \S & The name of section \N\cr
\+   {\tt section [} \N {\tt ]} & \N & The number of the section card \N is in, or 0\cr
\+   {\tt prevform} & \S & The name of the previous accessed form file\cr
\+   {\tt switch (} \S, \S {\tt )} & \S & Database switch and/or query; see above\cr
\bigskip

\subsection Operating System Access

\+   {\it Operator} & {\it Type} & {\it Operation}\cr
\smallskip\hrule\smallskip
\+   {\tt system (} \S {\tt )} & \S & Execute a shell command and return the result as a string\cr
\+   {\tt \$} {\it envvar} & \S & Return the value of the environment variable {\it envvar}\cr
\+   {\tt host} & \S & The host name of the local host\cr
\+   {\tt user} & \S & The user's login name\cr
\+   {\tt uid} & \N & The user's numeric user ID\cr
\+   {\tt gid} & \N & The user's numeric group ID\cr
\+   {\tt access (} \S, \N {\tt )} & \N & 1 if the file name exists (if the number is 0), or if it can be accessed\cr
\+   && for execution (1), writing (2), and/or reading (4). See access(3).\cr
\+   {\tt beep} & \S & Ring the terminal bell, return a null string\cr
\+   {\tt error (} {\it args} {\tt )} & \S & Format a string like printf, print it in a window, return a null string\cr
\bigskip

\subsection Time Conversion

Dates and times are stored as number of seconds since
January 1, 1970. Durations are stored as number of seconds. Note that
this means thata time is a significantly larger number than a duration,
even if both have the same hh:mm string representation. The representation
depends on the date and time format selected in the Preferences menu.

\medskip
\+   {\it Operator} & {\it Type} & {\it Operation}\cr
\smallskip\hrule\smallskip
\+   {\tt time} & \S & The current time as hh:mm or hh:mm[ap] string\cr
\+   {\tt time (} \N {\tt )} & \S & Extract time part of the number, and format as hh:mm or hh:mm[ap] string\cr
\+   {\tt date} & \S & Today's date as dd.mm.yy or mm/dd/yy string\cr
\+   {\tt date (} \N {\tt )} & \S & Extract date part of the number, and format as dd.mm.yy or mm/dd/yy string\cr
\+   {\tt duration (} \N {\tt )} & \S & Convert a number of seconds to a hh:mm string\cr
\+   {\tt date} & \N & Current time in seconds since January 1, 1970\cr
\+   {\tt year (} \N {\tt )} & \N & Extract the (four-digit) year from a time\cr
\+   {\tt month (} \N {\tt )} & \N & Extract the month 1..12 from a time\cr
\+   {\tt day (} \N {\tt )} & \N & Extract the day 1..31 from a time\cr
\+   {\tt hour (} \N {\tt )} & \N & Extract the hour 0..23 from a time\cr
\+   {\tt minute (} \N {\tt )} & \N & Extract the minute 0..59 from a time\cr
\+   {\tt second (} \N {\tt )} & \N & Extract the second 0..59 from a time\cr
\+   {\tt julian (} \N {\tt )} & \N & Extract the julian date 0..365 from a time\cr
\+   {\tt leap (} \N {\tt )} & \N & 1 if the time is in a leap year, or 0 otherwise\cr
\medskip
